 /*  PCi Writer Simulator - Productivity battery life measurement
    Copyright © 2011, LEGRAND David
    Mail : david@pcinpact.com

    http://forum.pcinpact.com/topic/154156-pci-tool-battery-benchmark-suite/
    http://code.google.com/p/pci-bbs/

    This file is part of PCi Writer Simulator.

    PCi Writer Simulator is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    PCi Writer Simulator is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with PCi Writer Simulator.  If not, see <http://www.gnu.org/licenses/>.
 
    You're not allowed to use PC INpact name or logo without permission */

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using Microsoft.Win32;
using System.Threading;

namespace PCi_Writer_Simulator
{
    public partial class Form1 : Form
    {
        // On déclare les fonctions / variables qui seront utilisées pour la gestion du focus
        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();
        private Process base_process = null;

        // On définit les variables utiles
        string app_launch_name = "wordpad.exe";
        string dummy_file = "dummy.rtf";

        private string texte = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum rutrum dictum libero at egestas. Maecenas risus est, condimentum ac tempor eget, feugiat vitae eros. Sed dignissim neque a nisl tincidunt egestas. Etiam ac convallis nulla. Vivamus in ligula quis velit condimentum mollis. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque convallis vulputate mollis. Suspendisse potenti. Morbi ut tortor odio, et sagittis purus. Maecenas id leo molestie tortor sagittis mattis sed ac lorem. Quisque sodales, libero semper ullamcorper porttitor, nunc felis imperdiet orci, in posuere nunc felis vitae sem. Nunc ac nunc dui. Suspendisse mauris est, accumsan ut laoreet vitae, adipiscing vel nunc. Pellentesque sagittis, elit a eleifend vulputate, ligula odio egestas magna, sed aliquet justo massa ac neque. Vestibulum felis nibh, suscipit nec ultricies quis, posuere a tortor. Sed pellentesque auctor purus, vitae elementum metus placerat vel. Quisque non sapien in massa mattis tempus. Donec in tellus ac ligula sagittis rhoncus ac sed dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Duis semper neque quis magna semper non consectetur nulla tempus. Donec eu purus in nibh bibendum hendrerit. Phasellus porta varius urna, ut consequat turpis tempor at. In ac leo ac tellus pellentesque consequat. Curabitur congue fringilla mollis. Sed purus augue, ullamcorper a ullamcorper id, porttitor vitae eros. Fusce tincidunt adipiscing mauris, pharetra faucibus elit varius sagittis. Pellentesque adipiscing gravida nisl non varius. Proin laoreet fringilla nisi non consectetur. Etiam vestibulum rhoncus metus vitae ullamcorper. Integer sed nulla ante. Sed sodales aliquet ante. Etiam sodales, nibh a ornare eleifend, urna erat dictum tellus, in eleifend orci elit nec felis. Quisque at diam risus. Vestibulum felis risus, aliquam eu iaculis et, pulvinar id velit. Donec nec leo nec felis dapibus varius. Etiam a justo tellus, ac pellentesque metus. Vestibulum id enim vitae nunc adipiscing ultricies vel et ante. Integer viverra, enim in placerat tempus, erat magna faucibus augue, vehicula tincidunt magna sapien vel justo. Curabitur nec quam nunc, ut luctus ligula. Vivamus varius, est sit amet mattis dignissim, ipsum lorem elementum lorem, quis molestie mauris justo vitae sapien. Nam bibendum facilisis blandit. Duis vestibulum purus eget mi tristique vitae placerat leo auctor. Mauris scelerisque magna nec urna ultrices id pharetra lacus tincidunt. Nam lobortis massa ac turpis tempor a dictum dolor viverra. Integer tincidunt scelerisque dui, at dapibus massa congue eget. Aenean nisl nibh, placerat et ultricies viverra, tincidunt in dolor. Aenean eget sapien ut arcu porttitor tincidunt quis nec lacus. Nulla at risus ac ligula elementum porta. Mauris imperdiet ultricies sem, et mollis velit egestas vitae. Donec purus arcu, tincidunt eu semper in, placerat eu massa. Suspendisse potenti. Nunc quis arcu nulla, vitae commodo dui. Proin adipiscing, augue ac luctus rutrum, felis lacus viverra urna, a vehicula arcu enim sed libero. Duis condimentum molestie purus eu commodo. Maecenas porttitor enim sed libero sagittis et mattis eros vulputate. Maecenas condimentum ipsum sed nunc placerat venenatis. Aenean cursus, erat varius tincidunt egestas, orci metus semper augue, at gravida dolor mi nec odio. Suspendisse potenti. Donec ut nisl nunc. Aenean sodales lacus ligula. Sed ante arcu, eleifend eu rutrum sit amet, auctor eget mauris. Ut eget velit at erat molestie malesuada. Pellentesque lacinia tempor est, sed venenatis dolor congue nec. Proin ac felis eu nibh posuere malesuada vitae laoreet sapien. Praesent pellentesque tempor viverra. Ut vel nisi et magna porta varius vitae et velit. Vestibulum vel metus ipsum. Sed molestie mattis leo id dictum. Suspendisse sed dignissim nulla. Sed tristique, lectus in facilisis varius, nisl nibh congue libero, id aliquam tortor neque ut risus. Cras hendrerit suscipit odio id consectetur. Sed aliquam urna tellus, feugiat varius ligula. Fusce id libero id tellus lobortis congue sit amet id tellus. Vivamus elit libero, fringilla sed semper et, scelerisque eget turpis. Fusce odio purus, dignissim nec laoreet eu, faucibus ac ipsum. Fusce at nulla sem, lacinia sodales nulla. Nulla volutpat sapien vel sapien pulvinar eget porta felis luctus. Donec eu tincidunt tortor. Cras leo ante, dictum eu condimentum id, placerat ut tortor. Nunc ullamcorper lorem at dui adipiscing tincidunt. Donec vitae ipsum risus.";
        private int char_reader = 0;
        private long time = 0;

        // On définit les différents textes utiles
        string status_base_texte = "Status : ";
        string remain_base_texte = "Remaining battery life : ";
        string estimated_base_texte = "Remaining time : ";
        string unknown_estimated_base_texte = "Remaining time : ---";
        string error_focus = "Application lost focus. Test will be stopped";
        string error_mainwindow = "Application window not found. Test will be stopped";

        string pci_url = @"http://forum.pcinpact.com/topic/154156-pci-tool-battery-benchmark-suite/";

        public Form1()
        {
            InitializeComponent();

            // On applique le nom de l'application au titre de la fenêtre
            this.Text = Application.ProductName;
            // On affiche la version de l'application
            label_version.Text = String.Format("v{0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString());

            //On initialise le résultat
            Result_Update();

            // On démarre le timer dédié aux infos de la batterie et on les récupère une première fois
            // Ce timer ne sera jamais arrêté, puisqu'il sert à la mise à jour des infos de l'interface
            timer_batt.Start();
            Get_batt_infos();

            // On déclare l'évènement détectant le changement de PowerMode
            SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
        }

        // En cas d'appui sur le bouton Go
        private void button1_Click(object sender, EventArgs e)
        {
            // On initialise la valeur utilisée pour la lecture du texte et le résultat
            textBox_result.Text = "0 minute";

            // On créé le dummy file
            System.IO.File.WriteAllText(dummy_file, "");

            // On lance l'application et on garde le process pour une utilisation ultérieure
            // On change le curseur pour indiquer l'attente
            base_process = System.Diagnostics.Process.Start(app_launch_name, dummy_file);
            Cursor.Current = Cursors.WaitCursor;

            // TODO: Afficher une popup d'attente de chargement de la fenêtre principale de l'application testée
            for (int i = 0; i < 30; i++)
            {
                // Tant que l'application n'est pas lancée 
                if (base_process.MainWindowHandle == null || base_process.MainWindowHandle.ToInt32() == 0)
                {
                    // On attend une seconde et on rafraichit le process
                    Thread.Sleep(1000);
                    base_process.Refresh();
                }
            }

            // Dès que l'application est lancée, on remet le curseur en état
            Cursor.Current = Cursors.Default;

            // Si l'application testée n'a pas créé de fenêtre (plantée ou fermée), on affiche une erreur 
            if (base_process.MainWindowHandle == null || base_process.MainWindowHandle.ToInt32() == 0)
            {
                Nice_quit();
                MessageBox.Show(error_mainwindow, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }


            // Si tout est OK, on lance les deux timers principaux
            timer_writing.Start();
            timer_result.Start();
        }

        // A chaque tick du timer servant à l'écriture
        private void timer_writing_Tick(object sender, EventArgs e)
        {
            // On récupère le nom de la fenêtre active
            IntPtr handle = GetForegroundWindow();

            // Si la fenêtre active est identique à celle relevée au départ
            if (handle != null && base_process.MainWindowHandle != null && handle.Equals(base_process.MainWindowHandle))
            {
                // On lit tous les caractères du texte les uns après les autres
                if (char_reader < texte.Length)
                {
                    SendKeys.Send(texte[char_reader].ToString());
                    char_reader++;
                }
                // Quand tout le texte a été lu on rajoute des sauts de ligne, on sauvegarde (CTRL+S) et on retourne au début
                else
                {
                    for (int j = 0; j < 2; j++) SendKeys.Send("{ENTER}");
                    SendKeys.Send("^s");
                    char_reader = 0;
                }
            }
            // Si la fenêtre active n'est pas l'appli du test
            else
            {
                // On arrête le timer pour éviter les répétitions d'action
                timer_writing.Stop();

                // On notifie l'utilisateur du problème, et on stoppe le test
                Nice_quit();
                MessageBox.Show(error_focus, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        // A chaque tick du timer de résultat
        private void timer_result_Tick(object sender, EventArgs e)
        {
            // On incrémente le compteur et on le met à jour
            time += timer_result.Interval / 60000;
            Result_Update();
        }

        // A chaque tick du timer de l'affichage des données de la batterie
        private void timer_batt_Tick(object sender, EventArgs e)
        {
            // On récupère les infos sur la batterie
            Get_batt_infos();
        }

        // Fonction effectuant une fermeture propre de l'appli demandée
        private void Nice_quit()
        {
            // On arrête les deux timers principaux
            timer_writing.Stop();
            timer_result.Stop();

            // On remet à zéro le lecteur de caractères et le résultat
            char_reader = 0;
            time = 0;

            // On tue / libère le processus de l'application
            if (base_process != null && !base_process.HasExited)
            {
                base_process.Kill();
                base_process.Dispose();
            }
            base_process = null;
        }

        // En cas de fermeture de l'application, on quitte l'appli demandée proprement
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Nice_quit();
        }

        // Lorsque le résultat est modifié, on le log
        private void textBox_result_TextChanged(object sender, EventArgs e)
        {
            System.IO.File.WriteAllText("log.txt", textBox_result.Text);
        }

        // Quand on clique sur le label URL du site
        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            Process.Start(pci_url);
        }

        // Fonction qui récupère et affiche l'état de la batterie
        private void Get_batt_infos()
        {
            progressBar1.Value = (int)(100 * SystemInformation.PowerStatus.BatteryLifePercent);

            label1.Text = String.Format("{0}{1}", status_base_texte, SystemInformation.PowerStatus.BatteryChargeStatus);
            label2.Text = String.Format("{0}{1} %", remain_base_texte, 100 * SystemInformation.PowerStatus.BatteryLifePercent);

            // On affiche la batterie restante, sauf si le chiffre remonté est invalide (-1)
            if (SystemInformation.PowerStatus.BatteryLifeRemaining != -1)
            {
                TimeSpan remain = new TimeSpan(0, 0, SystemInformation.PowerStatus.BatteryLifeRemaining);
                label3.Text = String.Format("{0}{1} h {2} min {3} s", estimated_base_texte, remain.Hours, remain.Minutes, remain.Seconds);
            }
            else label3.Text = unknown_estimated_base_texte;
        }

        // Fonction appelée lorsque le PowerMode est modifié
        private void SystemEvents_PowerModeChanged(object sender,
                                  PowerModeChangedEventArgs e)
        {
            // On met à jour les informations de la batterie
            Get_batt_infos();
        }

        // Fonction de mise à jour du résultat avec gestion du pluriel
        private void Result_Update()
        {
            textBox_result.Text = String.Format("{0} minute{1}", time, time > 1 ? "s" : "");
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }
    }
}
